home *** CD-ROM | disk | FTP | other *** search
- /*
- **
- ** EVAL.C A floating point expression evaluator.
- ** Main source module.
- **
- ** Eval is a floating point expression evaluator.
- ** This file last updated in version 1.13
- ** For the version number, see eval.h
- ** Copyright (C) 1993 Will Menninger
- **
- ** To add a new constant to the Eval program
- ** -----------------------------------------
- ** 1. Update the size of MAXC in eval.h
- ** 2. Add your constant to the clist[] array below. Please keep the
- ** list in alphabetic order, and make sure that your contant's
- ** name does not exceed MAXNAMELEN (from eval.h)
- ** 3. If your constant is a physical constant with no indication
- ** of units in the name, either make sure it is in SI units, or change
- ** the print statement that claims all constants are in SI units.
- ** 4. Recompile ALL source modules.
- **
- **
- ** This program is free software; you can redistribute it and/or modify it
- ** under the terms of the GNU General Public License as published by the
- ** Free Software Foundation; either version 2 of the License, or any
- ** later version.
- **
- ** This program is distributed in the hope that it will be useful, but
- ** WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- ** General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License along
- ** with this program; if not, write to the Free Software Foundation, Inc.,
- ** 675 Mass Ave, Cambridge, MA 02139, USA.
- **
- ** The author until 9/93 can be contacted at:
- ** e-mail: willus@ilm.pfc.mit.edu
- ** U.S. mail: Will Menninger, 45 River St., #2, Boston, MA 02108-1124
- **
- **
- ** Originally written 5/89 in ANSI C
- **
- */
-
- #include "eval.h"
-
- static char tempname[80];
- static char wdir[100];
- static char rpath[200];
- static FILE *tempfile;
- static int linecount;
-
- static VAR clist[MAXC]= {
- {"_acres_per_sq_km",247.1},
- {"_air_density",1.293},
- {"_air_mol_mass",.02897},
- {"_atm_per_psi",.06804},
- {"_avagadro",6.0220e23},
- {"_boltzmann",1.3807e-23},
- {"_c",2.997925e8},
- {"_cm_per_in",2.54},
- {"_coulomb_const",8.98755e9},
- {"_deg_per_rad",57.2958},
- {"_earth_esc_spd",1.12e4},
- {"_earth_grav",9.80665},
- {"_earth_mass",5.98e24},
- {"_earth_radius",6.37e6},
- {"_earth_to_moon",3.844e8},
- {"_earth_to_sun",1.496e11},
- {"_eps0",8.85419e-12},
- {"_erg_per_joule",1e7},
- {"_eulers_const",.57721566490153286061},
- {"_ft_per_m",3.280839895},
- {"_g",6.672e-11},
- {"_gas_const",8.314},
- {"_gauss_per_tesla",1e4},
- {"_gm_per_oz",28.34952313},
- {"_golden_ratio",1.6180339887498948482},
- {"_h",6.6262e-34},
- {"_hbar",1.05459e-34},
- {"_joule_per_btu",1054.35},
- {"_joule_per_cal",4.184},
- {"_joule_per_ftlb",1.356},
- {"_joule_per_kwh",3.6e6},
- {"_kg_per_slug",14.59},
- {"_km_per_mi",1.609344},
- {"_knots_per_mph",.86897624},
- {"_lbs_per_kg",2.204622622},
- {"_lit_per_gal",3.785411784},
- {"_me",9.1095e-31},
- {"_mn",1.67495e-27},
- {"_moon_grav",1.62},
- {"_moon_mass",7.35e22},
- {"_moon_period",2360448.},
- {"_moon_radius",1.738e6},
- {"_mp",1.67265e-27},
- {"_mu0",1.256637e-6},
- {"_oz_per_gal",128.},
- {"_pasc_per_atm",101325.},
- {"_pasc_per_psi",6895.},
- {"_pasc_per_torr",133.32},
- {"_pi",3.14159265358979323846},
- {"_qe",1.60219e-19},
- {"_solar_const",1350.},
- {"_speed_sound",331.},
- {"_sun_mass",1.99e30},
- {"_sun_radius",6.96e8},
- {"_watts_per_hp",745.712},
- {"_zero_deg_cels",273.15}
- };
-
- static char *license =
- "Eval, a floating point expression evaluator, version %s\n"
- "Copyright (C) 1993 Will Menninger\n"
- "This program is freely redistributable under certain restrictions.\n"
- "It comes with absolutely no warranty.\n"
- "Type '\x3f\x3f' for more information, or '?' for brief help.\n";
-
-
- static int process_file(char *filename,int bequiet,VARPTR vlist,VARPTR clist);
- static BOOLEAN process_line(FILE *stream,int showinp,int showout,VARPTR vlist,
- VARPTR clist,char *pinput);
- static void init_varlist(VARPTR vlist);
- static void var_copy(VARPTR dest,VARPTR source);
- static int print_help(FILE *stream,int extended,int page,char *s);
- static int more(char *text,char *input,int pause);
- static void print_oplist(void);
- static int print_varlist(FILE *s,char *input,VARPTR list,int max);
- static void print_stats(void);
- static int nextline(char *s,FILE *stream);
- static void close_temp(int showout);
- static int srchpath(char *name);
- static void cwdir(char *name);
-
-
- int main(int argc,char *argv[])
-
- {
- VAR vlist[MAXV];
- char arg[MAXINPUT+1];
- int i,nargs,c;
-
-
- init_varlist(vlist);
- wdir[0]=EOS;
- rpath[0]=EOS;
- setobase(10);
- setibase(10);
- set_scinote(0);
- set_fix(0);
- set_sigfig(10);
- set_dplace(10);
- set_maxexp(5);
- tempfile=NULL;
- arg[0]=EOS;
- for (i=1;i<argc;i++)
- {
- if (strlen(arg)+strlen(argv[i])>MAXINPUT-1)
- break;
- if (i>1)
- strcat(arg," ");
- strcat(arg,argv[i]);
- }
- nargs=i-1;
- if (arg[0]=='@')
- {
- for (i=1;arg[i]==' ';i++);
- c=arg[i];
- }
- else
- c=arg[0];
- if (c==EOS)
- nargs=0;
- if (nargs && c!='<')
- {
- process_line(NULL,0,1,vlist,clist,arg);
- close_temp(1);
- return(0);
- }
- printf(license,VERSION);
- if (nargs)
- process_line(NULL,1,1,vlist,clist,arg);
- while (!process_line(stdin,0,1,vlist,clist,""));
- close_temp(1);
- return(0);
- }
-
-
- /*
- ** process_file
- **
- ** Sends all of the lines from file, filename, to Eval for processing.
- **
- ** Returns 1 if a quit was encountered in the file, 0 otherwise
- **
- */
-
- static int process_file(char *filename,int bequiet,VARPTR vlist,VARPTR clist)
-
- {
- FILE *s;
- int status;
-
- s=fopen(filename,"r");
- if (s==NULL)
- {
- printf("File %s not found.\n",filename);
- return(0);
- }
- while (1)
- {
- status=process_line(s,!bequiet,!bequiet,vlist,clist,"");
- if (status==1 || status==2)
- break;
- }
- fclose(s);
- return(status==1 ? 1 : 0);
- }
-
-
- /*
- ** process_line
- **
- ** Processes one line of input from stream.
- ** If showinp is NZ, the input is printed to stdout.
- ** If showout is NZ, all output is printed to stdout.
- **
- ** If stream==NULL, input is taken from string: pinput
- **
- ** Returns: 1 if "quit" (or similar command) is read.
- ** 2 if end of file
- ** 0 otherwise.
- **
- */
-
- static BOOLEAN process_line(FILE *stream,int showinp,int showout,VARPTR vlist,
- VARPTR clist,char *pinput)
-
- {
- char rname[100];
- char input[MAXINPUT+1];
- int bequiet,i,m0,m1,m2,n,nargs;
-
- input[0]=EOS;
- if (stream!=NULL)
- {
- if (!nextline(input,stream))
- return(2);
- }
- else
- strcpy(input,pinput);
-
- while (1)
- {
- if (input[0]=='@')
- {
- bequiet=1;
- for (i=1;input[i]==' ' || input[i]=='\t';i++);
- }
- else
- {
- bequiet=0;
- i=0;
- }
- if (input[i]!='<' && input[i]!='>' && tempfile!=NULL)
- {
- fprintf(tempfile,"%s\n",&input[i]);
- linecount++;
- }
- if (showinp && !bequiet && input[i]!=EOS)
- printf("%s%s\n",PROMPT,input);
- if (!strcmp(&input[i],"stop") || !strcmp(&input[i],"quit") ||
- !strcmp(&input[i],"exit") || !strcmp(&input[i],"end"))
- return(1);
- if (input[i]==EOS)
- {
- if (!showinp && !bequiet && showout)
- printf("Type '?' or 'help' for help.\n");
- return(0);
- }
- if (!strncmp(&input[i],"help",4) &&
- (input[i+4]==' ' || input[i+4]=='\t' || input[i+4]==EOS))
- {
- if (input[i+4]!=EOS)
- n=atoi(&input[i+4]);
- else
- n=0;
- if (showout && !bequiet && print_help(stream,1,n,input))
- continue;
- else
- break;
- }
- if (input[i]=='<' || input[i]=='>')
- {
- n=input[i];
- for (i++;input[i]==' ' || input[i]=='\t';i++);
- if (n=='<')
- {
- if (input[i]==EOS)
- {
- printf("Must specify a file name after <.\n");
- return(0);
- }
- strcpy(rname,&input[i]);
- if (!srchpath(rname))
- {
- printf("Cannot find %s in read path.\n",rname);
- return(0);
- }
- return(process_file(rname,bequiet || !showout,vlist,clist));
- }
- close_temp(showout && !bequiet);
- if (input[i]!=EOS)
- {
- strcpy(tempname,&input[i]);
- cwdir(tempname);
- tempfile=fopen(tempname,"w");
- linecount=0;
- if (tempfile==NULL)
- printf("Cannot open %s for output.\n",tempname);
- else
- if (showout && !bequiet)
- printf("Script file %s begun.\n",tempname);
- }
- return(0);
- }
- nargs=1;
- m0=i;
- showout=(showout && !bequiet);
- while (1)
- {
- for (;!isspace(input[i]) && input[i]!=EOS;i++);
- if (nargs==1)
- m1=i-m0;
- if (input[i]==EOS)
- break;
- for (;isspace(input[i]);i++);
- if (input[i]==EOS)
- break;
- nargs++;
- if (nargs==2)
- m2=i;
- if (nargs>2)
- break;
- }
- if (nargs==2)
- n=atoi(&input[m2]);
- if (!strncmp(&input[m0],"rpath",m1))
- {
- if (nargs==2)
- {
- strcpy(rpath,&input[m2]);
- if (showout)
- printf("Read path set to %s\n",rpath);
- }
- else
- {
- rpath[0]=EOS;
- if (showout)
- printf("Read path cleared.\n");
- }
- break;
- }
- if (!strncmp(&input[m0],"wdir",m1))
- {
- if (nargs==2)
- {
- strcpy(wdir,&input[m2]);
- if (showout)
- printf("Write dir set to %s\n",wdir);
- }
- else
- {
- wdir[0]=EOS;
- if (showout)
- printf("Write dir set to current dir.\n");
- }
- break;
- }
- if (!strncmp(&input[m0],"obase",m1) && nargs==2 && n>0)
- {
- if (n<2 || n>36)
- {
- printf("Output base must be between 2 and 36.\n");
- break;
- }
- setobase(n);
- if (showout)
- printf("Output base set to %d.\n",n);
- break;
- }
- if (!strncmp(&input[m0],"ibase",m1) && nargs==2 && n>0)
- {
- if (n<2 || n>36)
- {
- printf("Input base must be between 2 and 36.\n");
- break;
- }
- setibase(n);
- if (showout)
- printf("Input base set to %d.\n",n);
- break;
- }
- if (!strncmp(&input[m0],"sci",m1) && nargs<2)
- {
- set_scinote(!get_scinote());
- if (showout)
- printf("Scientific notation %s.\n",get_scinote() ? "ON":"OFF");
- break;
- }
- if (!strncmp(&input[m0],"fix",m1) && nargs<2)
- {
- set_fix(!get_fix());
- if (showout)
- printf("Fixed precision %s.\n",get_fix() ? "ON":"OFF");
- break;
- }
- if (!strncmp(&input[m0],"sigfig",m1) && nargs==2)
- {
- if (n>DBL_MANT_DIG)
- printf("Significant figures limited to %d.\n",
- DBL_MANT_DIG);
- else
- {
- set_sigfig(n);
- if (showout)
- {
- printf("Significant figures = ");
- if (n>0)
- printf("%d\n",n);
- else
- printf("max\n");
- }
- }
- break;
- }
- if (!strncmp(&input[m0],"maxexp",m1) && nargs==2)
- {
- set_maxexp(n);
- if (showout)
- {
- if (n<0)
- printf("Exponent limit turned off.\n");
- else
- printf("Exponent limit = %d\n",n);
- }
- break;
- }
- if (!strncmp(&input[m0],"dplace",m1) && nargs==2)
- {
- if (n<-70 || n>70)
- printf("Decimal place must be between -70 and 70.\n");
- else
- {
- set_dplace(n);
- if (showout)
- printf("Decimal place = %d\n",n);
- }
- break;
- }
- if (input[m0]!='?')
- {
- evaluate(&input[m0],showout,vlist,clist);
- break;
- }
- if (!strcmp(&input[m0],"?"))
- if (showout && print_help(stream,0,0,input))
- continue;
- else
- break;
- for (i=m0+1;isspace(input[i]);i++);
- if (input[i]=='?')
- {
- if (input[i+1]!=EOS)
- n=atoi(&input[i+1]);
- else
- n=0;
- if (showout && print_help(stream,1,n,input))
- continue;
- else
- break;
- }
- switch (tolower((int)input[i]))
- {
- case 'v':
- if (showout && print_varlist(stream,input,vlist,MAXV))
- continue;
- break;
- case 'c':
- if (showout)
- {
- printf("All physical constants are in SI units unless the "
- "name of the variable\nindicates otherwise.\n");
- if (print_varlist(stream,input,clist,MAXC))
- continue;
- }
- break;
- case 'f':
- if (showout)
- if (print_funclist(stream,input,tolower((int)input[i+1])=='l'))
- continue;
- break;
- case 'o':
- if (showout)
- print_oplist();
- break;
- case 's':
- if (showout)
- print_stats();
- break;
- default:
- printf("\"%s\" is an unknown query.\n",&input[i]);
- break;
- }
- break;
- }
- return(0);
- }
-
-
- /*
- ** insert_var(VARPTR new,VARPTR vlist)
- **
- ** Inserts a the new variable into the current list of variables.
- ** Returns 1 if successful, 0 if list is full.
- **
- */
-
- BOOLEAN insert_var(VARPTR new,VARPTR vlist)
-
- {
- BOOLEAN found;
- int i,j,k;
-
- found=search_varlist(new,vlist,&i,MAXV);
- if (!found && vlist[MAXV-1].name[0]!=EOS)
- return(0);
- if (found)
- var_copy(&vlist[i],new);
- else
- {
- for (j=i;j<MAXV-1 && vlist[j].name[0]!=EOS;j++);
- for (k=j;k>i;k--)
- var_copy(&vlist[k],&vlist[k-1]);
- var_copy(&vlist[i],new);
- }
- return(1);
- }
-
-
- /*
- ** init_varlist(VARPTR vlist)
- **
- ** Sets all variable names to EOS, representing empty spaces
- **
- */
-
- static void init_varlist(VARPTR vlist)
-
- {
- int i;
-
- for (i=0;i<MAXV;i++)
- vlist[i].name[0]=EOS;
- }
-
- /*
- ** var_copy(VARPTR dest,VARPTR source)
- **
- ** copies one variable to another
- **
- */
-
- static void var_copy(VARPTR dest,VARPTR source)
-
- {
- strcpy(dest->name,source->name);
- dest->value=source->value;
- }
-
-
- /*
- ** search_varlist(VARPTR var,VARPTR vlist,int *n,int max)
- **
- ** Searches through a variable list for the variable specified. If
- ** found, returns 1 else returns 0. The position for insertion is
- ** returned in (*n). The search is binary for fast response.
- **
- */
-
- BOOLEAN search_varlist(VARPTR var,VARPTR vlist,int *n,int max)
-
- {
- int step,c;
-
- (*n)=step=max>>1;
- while (1)
- {
- if (step>1)
- step>>=1;
- if (vlist[(*n)].name[0]==EOS)
- {
- if ((*n)==0)
- return(0);
- (*n)=(*n)-step;
- continue;
- }
- if (!(c=strcmp(var->name,vlist[(*n)].name)))
- break;
- if (c>0)
- {
- if ((*n)==max-2 || vlist[(*n)+1].name[0]==EOS)
- {
- (*n)=(*n)+1;
- if (vlist[(*n)].name[0]!=EOS)
- return(!strcmp(var->name,vlist[(*n)].name));
- else
- return(0);
- }
- (*n)=(*n)+step;
- continue;
- }
- if ((*n)==0 || strcmp(var->name,vlist[(*n)-1].name)>0)
- return(0);
- (*n)=(*n)-step;
- }
- return(1);
- }
-
-
- /*
- ** print_help(void)
- **
- ** Prints instructions on how to use the expression evaluator.
- **
- */
-
- static int print_help(FILE *stream,int extended,int page,char *s)
-
- {
- extern char *bhelp;
- extern char *ehelp;
- int i,j;
-
- if (extended)
- for (i=0,j=0;ehelp[j]!=EOS && i<page-1;j++)
- if (ehelp[j]=='\f')
- {
- j++;
- i++;
- }
-
- return (more(extended ? &ehelp[j] : bhelp,s,stream==stdin));
- }
-
-
- static int more(char *text,char *input,int pause)
-
- {
- int nl;
- int c,in,istart;
-
- in=-1;
- while (1)
- {
- istart=in+1;
- for (nl=0;nl<NLINES;nl++)
- {
- for (in++;text[in]!='\f' && text[in]!='\n' && text[in]!=EOS;in++);
- if (text[in]==EOS || text[in]=='\f')
- break;
- }
- if (text[in]==EOS || text[in+1]==EOS)
- {
- printf("%s\n",&text[istart]);
- break;
- }
- if (text[in]=='\f')
- in--;
- c=text[in+1];
- text[in+1]=EOS;
- printf("%s\n",&text[istart]);
- text[in+1]=c;
- if (pause)
- {
- printf("Press <ENTER> for more...\n");
- input[0]=EOS;
- nextline(input,stdin);
- if (input[0]!=EOS)
- return(1);
- printf("\n");
- }
- if (c=='\f')
- in+=2;
- }
- return(0);
- }
-
-
- /*
- ** print_oplist(void)
- **
- ** Prints list of operands
- **
- */
-
- static void print_oplist(void)
-
- {
- static char *oplist =
- "\nUnary operators:\n"
- " + positive\n"
- " - negative\n"
- " ~ bit-wise NOT\n\n"
- "Binary operators: (in order of precedence)\n"
- " ^ power*\n"
- " * / % multiply, divide, modulo\n"
- " + - add, subtract\n"
- " << >> bit-shift left, right\n"
- " & bit-wise AND\n"
- " ? bit-wise XOR*\n"
- " | bit-wise OR\n\n"
- "* - different from C\n\n";
- printf("%s",oplist);
- }
-
-
- /*
- ** print_varlist(FILE *s,char *input,VARPTR list,int max)
- **
- ** Prints out a list of constants or variables and their values
- **
- */
-
- static int print_varlist(FILE *s,char *input,VARPTR list,int max)
-
- {
- char bigbuf[MAXOUTLEN];
- char bigline[MAXOUTLEN];
- int i,j,k,l,n,m1,m2,nc,cw,nr,li,c;
-
- for (m1=m2=0,i=0;i<max && list[i].name[0]!=EOS;i++)
- {
- if ((l=strlen(list[i].name))>m1)
- m1=l;
- baseconv(list[i].value,bigbuf);
- if ((l=strlen(bigbuf))>m2)
- m2=l;
- }
- n=i;
- if (!n)
- {
- printf("There are no currently assigned variables.\n");
- return(0);
- }
- cw=m1+m2+7;
- nc=(SCRWIDTH+3)/cw;
- if (nc<=0)
- nc=1;
- nr=(i+nc-1)/nc;
- for (i=0;i<nr;i++)
- {
- li=0;
- for (j=0;j<nc;j++)
- {
- k=i+j*nr;
- if (k>=n)
- break;
- for (l=0;(c=list[k].name[l])!=EOS;l++)
- bigline[li++]=c;
- for (;l<m1;l++)
- bigline[li++]=' ';
- baseconv(list[k].value,bigbuf);
- bigline[li++]=' ';
- bigline[li++]='=';
- bigline[li++]=' ';
- for (l=0;(c=bigbuf[l])!=EOS;l++)
- bigline[li++]=c;
- if (j<nc-1)
- for (;l<m2+4;l++)
- bigline[li++]=' ';
- }
- bigline[li]=EOS;
- printf("%s\n",bigline);
- if (s==stdin && i!=nr-1 && ((i+3)%NLINES)==0)
- {
- printf("\nPress <ENTER> for more...\n");
- input[0]=EOS;
- nextline(input,s);
- if (input[0]!=EOS)
- return(1);
- printf("\n");
- }
- }
- printf("\n");
- return(0);
- }
-
-
- static void print_stats(void)
-
- {
- int ib,ob;
-
- ib=getibase();
- ob=getobase();
- printf("\nExpression evaluator, version %s\n",VERSION);
- print_outtype();
- printf("Default input base: %d\n",ib);
- printf("Default output base: %d\n\n",ob);
- printf("Base %d accuracy: %d digits\n",ib,precision(ib));
- if (ob!=ib)
- printf("Base %d accuracy: %d digits\n",ob,precision(ob));
- printf("\n");
- printf("Read path: %s\n",rpath[0]==EOS ? "None" : rpath);
- printf("Write dir: %s\n",wdir[0]==EOS ? "Current dir" : wdir);
- printf("\n");
- }
-
-
- /*
- ** void fixup(char *s)
- **
- ** Removes white space from beginning and end of string. Also removes
- ** \n from end of string, and converts entire string to lower case.
- **
- */
-
- void fixup(char *s)
-
- {
- int i,j;
-
- for (i=0;isspace(s[i]);i++);
- for (j=0;s[i]!='\n' && s[i]!=EOS;j++,i++)
- s[j]=tolower((int)s[i]);
- for (j--;j>=0 && isspace(s[j]);j--);
- s[j+1]=EOS;
- }
-
-
- static int nextline(char *s,FILE *stream)
-
- {
- while (1)
-
- {
- if (stream==stdin)
- printf("%s",PROMPT);
- if (fgets(s,MAXINPUT,stream)==NULL)
- return(0);
- fixup(s);
- if (s[0]!=';')
- break;
- }
- return(1);
- }
-
-
- static void close_temp(int showout)
-
- {
- if (tempfile!=NULL)
- {
- fclose(tempfile);
- tempfile=NULL;
- if (showout)
- printf("%d lines written to %s.\n",linecount,tempname);
- }
- }
-
-
- static int srchpath(char *name)
-
- {
- char buf[100];
- int i,j;
- int checked;
- FILE *f;
-
- i=0;
- strcpy(buf,name);
- checked=0;
- while (1)
- {
- for (j=0;rpath[i]!=EOS && rpath[i]!=';';i++,j++)
- buf[j]=rpath[i];
- buf[j]=EOS;
- if (checked && !j && rpath[i]==EOS)
- return(0);
- while (rpath[i]==';')
- i++;
- strcat(buf,name);
- if (j || !checked)
- {
- if (!j)
- checked=1;
- f=fopen(buf,"r");
- if (f!=NULL)
- break;
- }
- }
- fclose(f);
- strcpy(name,buf);
- return(1);
- }
-
-
- static void cwdir(char *name)
-
- {
- char buf[100];
- FILE *f;
-
- strcpy(buf,wdir);
- strcat(buf,name);
- f=fopen(buf,"w");
- if (f==NULL)
- return;
- fclose(f);
- strcpy(name,buf);
- }
-